﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RobotMapper;
using Entity;
using System.Reflection;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    [TestClass]
    public class 配置测试
    {
        [TestMethod]
        public void 测试配置Bind()
        {
            Mapper.Initialize(creator =>
            {
                creator.CreatMap<User, DTO.User>(config =>
                {
                    config.Bind(x => x.User12.Name, y => y.UserName);
                    config.BindName(x => x.User12, y => y.UserName);
                    config.Ignore(y => y.Roles);
                });
            });
        }

        [TestMethod]
        public void 测试配置规则转换()
        {
            Mapper.Initialize(creator =>
            {
                creator.CreatMap<User, DTO.User>(config =>
                {
                    config.Bind(x => x.User12.Name, y => y.UserName);
                });
            });
            var user = TestHelper.创建自引用User();
            var newuser = user.RobotMap<User, DTO.User>();
            Assert.AreEqual(user.User12.Name, newuser.UserName);
        }
        
        [TestMethod]
        public void 测试即用即配绑定()
        {
            var user = TestHelper.创建自引用User();
            var newuser = user.RobotMap<User, DTO.User>(config =>
            {
                config.Bind(x => x.User12?.Name, y => y.UserName);
            });
            Assert.AreEqual(user.User12?.Name, newuser.UserName);
        }

        [TestMethod]
        public void 测试即用即配忽略()
        {
            var user = TestHelper.创建扁平化User();
            var newuser = user.RobotMap<User, DTO.User>(config =>
            {
                config.Ignore(y => y.Code);
                config.Ignore("Department", "Name");
            });
            Assert.IsNull(newuser.Code);
            Assert.IsNull(newuser.Department);
            Assert.IsNull(newuser.Name);
        }

        [TestMethod]
        public void 测试忽略规则转换()
        {
            Mapper.Initialize(creator =>
            {
                creator.ClearConfig();
                creator.CreatMap<User, DTO.User>(config =>
                {
                    config.Ignore(y => y.Code);
                    config.Ignore("Department", "Name");
                });
            });
            var user = TestHelper.创建扁平化User();
            var newuser = user.RobotMap<User, DTO.User>();
            Assert.IsNull(newuser.Code);
            Assert.IsNull(newuser.Department);
            Assert.IsNull(newuser.Name);
        }

        [TestMethod]
        public void 测试指定属性名绑定()
        {
            Mapper.Initialize(creator =>
            {
                creator.ClearConfig();
            });
            var obj = TestHelper.GetPropertyCustomClass();
            //本次映射由于没有做配置 因此User1->User2不会映射
            var newObj = obj.RobotMap<PropertyCustomClass, DTO.PropertyCustomClass>(config=> 
            {
                //config.BindName(x => x.User1, y => y.User2);
            });
            Assert.IsNotNull(obj.User1);
            Assert.IsNull(newObj.User2);

            //本次将映射（因为指定属性名需要映射）
            newObj = obj.RobotMap<PropertyCustomClass, DTO.PropertyCustomClass>(config =>
            {
                config.BindName(x => x.User1, y => y.User2);
            });
            Assert.IsNotNull(obj.User1);
            Assert.IsNotNull(newObj.User2);
            Assert.AreEqual(obj.User1.Name, newObj.User2.Name);
        }

        [TestMethod]
        public void 测试表达式树的方法()
        {
            Expression<Func<int, int, int>> exp = (a, b) => a + b;
            var user = new ExpTestObject()
            {
                FirstName = "Hai.liu",
                ExpTestObjectItem = new ExpTestObjectItem() { Name = "Hello" },
            };
            var newUser = TransExp<ExpTestObject, DTO.ExpTestObject>(user);
            Expression<Func<ExpTestObject, DTO.ExpTestObject>> expression2 = (x) => new DTO.ExpTestObject()
            {
                FirstName = x.FirstName,
                ExpTestObjectItem = new DTO.ExpTestObjectItem() { Name = x.ExpTestObjectItem.Name },
            };
        }

        [TestMethod]
        public void 测试表达式树的方法2()
        {
            Expression<Func<int, int, int>> exp = (a, b) => a + b;
            var user = new ExpTestObject()
            {
                FirstName = "Hai.liu",
                ExpTestObjectItem = new ExpTestObjectItem() { Name = "Hello" },
            };
            var newUser = TransExp<ExpTestObject, DTO.ExpTestObject>(user);
            Expression<Func<ExpTestObject, DTO.ExpTestObject>> expression2 = (x) => new DTO.ExpTestObject()
            {
                FirstName = x.FirstName,
                ExpTestObjectItem = new DTO.ExpTestObjectItem() { Name = x.ExpTestObjectItem.Name },
            };
        }

        [TestMethod]
        public void 测试绑定的父子类规则()
        {
            var child = TestHelper.创建子类实例();
            Mapper.Initialize(creator =>
            {
                creator.ClearConfig();
                creator.CreatMap<Parent, DTO.Parent>(config =>
                 {
                     //父类属性与父类属性绑定
                     config.Bind(x => x.BB, y => y.AA);
                 });
            });
            //但是子类与子类之间映射
            var newChild = child.RobotMap<Children, DTO.Children>();
            Assert.IsTrue(newChild.AA == child.BB);
        }

        private static MemberInitExpression Bind(Type sourceType,Type targetType)
        {
            //构建参数 传入T
            ParameterExpression parameterExpression = Expression.Parameter(sourceType, "p");
            //将M的所有属性通过T绑定
            List<MemberBinding> memberBindingList = new List<MemberBinding>();

            PropertyInfo[] sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            PropertyInfo[] destinationProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var item in destinationProperties)
            {
                var sourceProperty = sourceType.GetProperty(item.Name);
                if (sourceProperty == null) continue;

                var sourcePropertyType = sourceProperty.PropertyType;
                var targetPropertyType = item.PropertyType;

                //获取源属性
                MemberExpression property = Expression.Property(parameterExpression, sourceProperty);
                
                if (item.Name == "ExpTestObjectItem")
                {
                    //对于自定义属性 需要遍历
                    var exp = Bind(sourcePropertyType,targetPropertyType);
                    //MemberBinding memberBinding = Expression.Bind(item, Expression.MemberInit(Expression.New(typeof(M)), new MemberBinding[]
                    //{
                    //    //Expression.Bind()
                    //}));
                    //memberBindingList.Add(memberBinding);
                }
                else
                {
                    //对于普通属性直接绑定
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
            }

            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(targetType), memberBindingList);
            return memberInitExpression;
        }

        #region 表达式树
        private static void TT()
        {
            ParameterExpression parameterExpression2 = null;
            Expression<Func<ExpTestObject, DTO.ExpTestObject>> expression2 =
             Expression.Lambda<Func<ExpTestObject, DTO.ExpTestObject>>(Expression.MemberInit(Expression.New(typeof(ExpTestObject)), new MemberBinding[]
             {
             }), //第一个参数：绑定表达式树
             new ParameterExpression[] { parameterExpression2 }//第二个参数：参数表达式树
             );
        }

        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
        
        private static Expression<Func<T, M>> TransExp<T, M>(T tIn)
            where T : class
            where M : class
        {
            //构建参数 传入T
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            //将M的所有属性通过T绑定
            List<MemberBinding> memberBindingList = new List<MemberBinding>();

            PropertyInfo[] sourceProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            PropertyInfo[] destinationProperties = typeof(M).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var item in destinationProperties)
            {
                var sourceProperty = typeof(T).GetProperty(item.Name);
                if (sourceProperty == null) continue;

                //获取源属性
                MemberExpression property = Expression.Property(parameterExpression, sourceProperty);

                var destinationPropertyType = item.PropertyType;
                if (item.Name == "ExpTestObjectItem")
                {
                    //对于自定义属性 需要遍历
                    //MemberBinding memberBinding = Expression.Bind(item, Expression.MemberInit(Expression.New(typeof(M)), new MemberBinding[]
                    //{
                    //    //Expression.Bind()
                    //}));
                    //memberBindingList.Add(memberBinding);
                }
                else
                {
                    //对于普通属性直接绑定
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
            }

            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(M)), memberBindingList);
            Expression<Func<T, M>> lambda = Expression.Lambda<Func<T, M>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
            return lambda;
        }
        #endregion
    }
}